﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Inscriptionem.Areas.Inscriptionem.Models.Enums;
using Inscriptionem.Areas.Inscriptionem.Models.Requests;
using Inscriptionem.Areas.Inscriptionem.Models.Views;
using Inscriptionem.Authorization;
using Inscriptionem.Extensions;

namespace Inscriptionem.Areas.Inscriptionem.Controllers
{
    [InscriptionemAuthorize(MemberRole.Admin)]
    public class LanguageController : Controller
    {
        private readonly ORM.DB DB;
        public LanguageController()
        {
            DB = new ORM.DB();
        }

        public ActionResult Index()
        {
            return View("Index", new LanguageCollectionViewModel());
        }

        [HttpPost]
        public ActionResult Add(LanguageRequestModel model)
        {
            var result = new LanguageViewModel();
            model.CopyTo(result);

            result.Error = ValidateLanguageAddModel(result);

            if (result.Error == LanguageError.None)
            {
                try
                {
                    // Save
                    if (result.IsDefault)
                    {
                        var existingLanguage = DB.Languages.FirstOrDefault(l => l.IsDefault);
                        if (existingLanguage != null)
                        {
                            existingLanguage.IsDefault = false;
                            existingLanguage.ModifiedDate = DateTime.Now;
                        }
                    }

                    var language = new ORM.Language()
                                       {
                                           Name = result.Name.Trim(),
                                           LocalizedName = result.LocalizedName.Trim(),
                                           IsDefault = result.IsDefault,
                                           Order = result.Order,
                                           CreatedDate = DateTime.Now,
                                           ModifiedDate = DateTime.Now
                                       };

                    DB.AddToLanguages(language);
                    DB.SaveChanges();
                }
                catch (Exception)
                {
                    result.Error = LanguageError.Other;
                }
            }

            if(result.Error == LanguageError.None)
            {
                return RedirectToAction("Index");
            }

            return View("Add", result);
        }

        [HttpPost]
        public ActionResult Edit(LanguageRequestModel model)
        {
            var result = new LanguageViewModel();
            model.CopyTo(result);

            // Not the best way to check if "Edit" button was pressed
            if (result.ID > 0 && string.IsNullOrWhiteSpace(result.Name) && string.IsNullOrWhiteSpace(result.LocalizedName))
            {
                var language = DB.Languages.FirstOrDefault(l => l.ID == result.ID);
                if (language == null)
                {
                    // Language not found
                    return RedirectToAction("Index");
                }

                result.Order = language.Order;
                result.Name = language.Name;
                result.LocalizedName = language.LocalizedName;
                result.IsDefault = language.IsDefault;

                return View("Edit", result);
            }

            // Validate
            result.Error = ValidateLanguageEditModel(result);
            if (result.Error == LanguageError.None)
            {
                // Save changes
                try
                {
                    var language = DB.Languages.FirstOrDefault(l => l.ID == result.ID);

                    if (language == null)
                    {
                        return RedirectToAction("Index");
                    }

                    language.Order = result.Order;
                    language.Name = result.Name.Trim();
                    language.LocalizedName = result.LocalizedName.Trim();
                    language.ModifiedDate = DateTime.Now;

                    DB.SaveChanges();

                    return RedirectToAction("Index");
                }
                catch (Exception)
                {
                    result.Error = LanguageError.Other;
                }
            }

            return View("Edit", result);
        }

        [HttpPost]
        public ActionResult Delete(int ID)
        {
            if(ID <= 0)
            {
                return RedirectToAction("Index");
            }

            var language = DB.Languages.FirstOrDefault(l => l.ID == ID);
            if (language == null)
            {
                return RedirectToAction("Index");
            }

            LanguageError result = LanguageError.None;

            try
            {
                if (DB.Languages.Count() == 1)
                {
                    result = LanguageError.LanguageUndeletable;
                }
                else if (language.Sections.Any())
                {
                    result = LanguageError.LanguageHasContent;
                }
                else
                {
                    if (language.IsDefault)
                    {
                        var defaultLanguage = DB.Languages.First(l => l.ID != ID);
                        defaultLanguage.IsDefault = true;
                        defaultLanguage.ModifiedDate = DateTime.Now;
                    }

                    DB.Languages.DeleteObject(language);
                    DB.SaveChanges();

                    return RedirectToAction("Index");
                }
            }
            catch (Exception)
            {
                result = LanguageError.Other;
            }

            return View("Delete", result);
        }

        public ActionResult Order()
        {
            return View("Order", new LanguageCollectionViewModel());
        }

        [HttpPost]
        public ActionResult Order(IList<LanguageOrderRequestModel> languages)
        {
            var error = ValidateLanguageOrderModel(languages);
            if (error == OrderError.None)
            {
                // Save
                foreach (var language in languages)
                {
                    var dbLanguage = DB.Languages.FirstOrDefault(l => l.ID == language.ID);
                    if (dbLanguage != null)
                    {
                        dbLanguage.Order = language.Order;
                        dbLanguage.ModifiedDate = DateTime.Now;
                    }
                }

                DB.SaveChanges();
            }

            return View("Order", new LanguageCollectionViewModel() {Error = error});
        }

        #region Implementation
        private OrderError ValidateLanguageOrderModel(IList<LanguageOrderRequestModel> Languages)
        {
            if (Languages == null || Languages.Count == 0)
            {
                return OrderError.Other;
            }

            if (Languages.Any(l => l.Order <= 0))
            {
                return OrderError.OrderNotValid;
            }

            var list = new List<int>();
            foreach (var language in Languages)
            {
                if (!list.Contains(language.Order))
                {
                    list.Add(language.Order);
                }
                else
                {
                    return OrderError.OrderDuplicate;
                }
            }

            return OrderError.None;
        }

        private LanguageError ValidateLanguageAddModel(LanguageViewModel Model)
        {
            var editValidateResult = ValidateLanguageEditModel(Model);
            if (editValidateResult != LanguageError.None)
            {
                return editValidateResult;
            }

            var language = DB.Languages.FirstOrDefault(l => l.Name.ToLower() == Model.Name.ToLower().Trim());
            if (language != null)
            {
                return LanguageError.LanguageAlreadyExists;
            }

            return LanguageError.None;
        }

        private LanguageError ValidateLanguageEditModel(LanguageViewModel Model)
        {
            if (string.IsNullOrWhiteSpace(Model.Name))
            {
                return LanguageError.LanguageEmpty;
            }

            if (string.IsNullOrWhiteSpace(Model.LocalizedName))
            {
                return LanguageError.LanguageLocalizationEmpty;
            }

            if (Model.Order <= 0)
            {
                return LanguageError.OrderNotValid;
            }

            var language = DB.Languages.FirstOrDefault(l => l.Order == Model.Order);
            if (language != null && language.ID != Model.ID)
            {
                return LanguageError.OrderAlreadyInUse;
            }

            return LanguageError.None;
        }
        #endregion
    }
}
